package com.zlyx.easy.core.factory;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;

import com.zlyx.easy.core.app.AppUtils;
import com.zlyx.easy.core.factory.defaults.annotations.FactoryBean;
import com.zlyx.easy.core.utils.ClassUtils;
import com.zlyx.easy.core.utils.StringUtils;

public abstract class ScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {

	private FactoryBean configAnno = this.getClass().getAnnotation(FactoryBean.class);

	private ResourceLoader resourceLoader;

	protected Class<? extends Annotation> scanAnnotation;

	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		this.scanAnnotation = configAnno.scanAnnotation();
		AnnotationAttributes annoAttrs = AnnotationAttributes
				.fromMap(importingClassMetadata.getAnnotationAttributes(scanAnnotation.getName()));
		if (annoAttrs == null) {
			return;
		}
		ClassPathScanner scanner = new ClassPathScanner(registry);

		if (resourceLoader != null) {
			scanner.setResourceLoader(resourceLoader);
		}

		Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
		if (!Annotation.class.equals(annotationClass)) {
			scanner.setAnnotationClass(annotationClass);
		}

		Class<?> markerInterface = annoAttrs.getClass("markerInterface");
		if (!Class.class.equals(markerInterface)) {
			scanner.setMarkerInterface(markerInterface);
		}

		Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
		if (!BeanNameGenerator.class.equals(generatorClass)) {
			scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
		}

		List<String> basePackages = new ArrayList<>();
		for (String pkg : annoAttrs.getStringArray("value")) {
			if (StringUtils.isNotEmpty(pkg)) {
				basePackages.add(pkg);
			}
		}
		for (String pkg : annoAttrs.getStringArray("basePackages")) {
			if (StringUtils.isNotEmpty(pkg)) {
				basePackages.add(pkg);
			}
		}
		for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) {
			basePackages.add(ClassUtils.getPackageName(clazz));
		}

		Class<?> mainClass = AppUtils.getMainClass();
		if (basePackages.isEmpty()) {
			ComponentScan componentScan = mainClass.getAnnotation(ComponentScan.class);
			if (componentScan != null) {
				for (String pkg : componentScan.value()) {
					if (StringUtils.isNotEmpty(pkg)) {
						basePackages.add(pkg);
					}
				}
				for (String pkg : componentScan.basePackages()) {
					if (StringUtils.isNotEmpty(pkg)) {
						basePackages.add(pkg);
					}
				}
				for (Class<?> clazz : componentScan.basePackageClasses()) {
					basePackages.add(ClassUtils.getPackageName(clazz));
				}
			}
		}
		if (basePackages.isEmpty()) {
			basePackages.add(ClassUtils.getPackageName(mainClass));
		}
		scanner.registerFilters();
		scanner.doScan(StringUtils.toStringArray(basePackages));
	}

	@Override
	public void setResourceLoader(ResourceLoader resourceLoader) {
		this.resourceLoader = resourceLoader;
	}
}
